<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2021/9/13
 * Time: 16:26
 */
namespace app\admin\controller;
use think\Controller;
use think\Db;
use think\Request;

class PayTest extends Controller
{
    protected $payApi = [
        'app' => 'https://api.mch.weixin.qq.com/hk/v3/transactions/jsapi',//APP支付
        'h5'  => 'https://api.mch.weixin.qq.com/hk/v3/transactions/jsapi',//H5支付
    ];//支付接口列表
    protected $queryApi = 'https://api.mch.weixin.qq.com/v3/pay/transactions/id/{transaction_id}';//查询订单接口
    protected $refundApi = 'https://api.mch.weixin.qq.com/v3/refund/domestic/refunds';//退单接口
    protected $refundNotify = '******';//退单回调自定义

    public function _initialize()
    {

    }

    /**
     * 配置
     */
    public function config(){
        return [
            'appid' => 'wx7e5c835298d1623c',
            'mchid' => '133761988',//商户号
            'serial_no' => '605BA945ED5504E13D68482AB58FB220F60BE5D9',//证书序列号
            'description' => '213123123',//应用名称
            'notify' => 'http://nmn.mm7.cn/pub_v2/pay/notify.v2.php',//支付回调
        ];
    }

    /**
     * 设置支付url
     * @param string $type  支付平台
     * @return mixed
     */
    public function getPayUrl($type = 'app'){
        return $this->payApi[$type];
    }

    /**
     * H5支付
     * @param $total  int  支付金额
     * @return mixed
     */
    public function h5Pay($total){
        //请求参数(报文主体)
        $config = $this->config();
        $body = [
            'appid' => $config['appid'],
            'mchid' => $config['mchid'],
            'description' => $config['description'],
            'out_trade_no' => $this->getOrderNo(),
            'notify_url' => $config['notify'],
            'amount' => [
                'total' => $total,
                'currency' => 'HKD'
            ],
            'trade_type'=> 'JSAPI',
            'merchant_category_code'=>'5111',
            "payer"=>["openid"=>"o9uzD4pdScqcKLXDaHjyp9fhYB-Y"],
        ];
        $headers = $this->sign('POST',$this->getPayUrl('h5'),json_encode($body));
        return $this->curl_post($this->getPayUrl('h5'),json_encode($body),$headers);
    }

    /**
     * APP支付
     * @param $total  int  支付金额
     * @return mixed
     */
    public function appPay($total){
        //请求参数(报文主体)
        $config = $this->config();
        $body = [
            'appid' => $config['appid'],
            'mchid' => $config['mchid'],
            'description' => $config['description'],
            'out_trade_no' => $this->getOrderNo(),
            'notify_url' => $config['notify'],
            'amount' => [
                'total' => $total,
                'currency' => 'CNY'
            ],
        ];
        $headers = $this->sign('POST',$this->getPayUrl(),json_encode($body));
        return $this->curl_post($this->getPayUrl(),json_encode($body),$headers);
    }

    /**
     * 预下单
     */
    public function preOrder(){
        $res = $this->h5Pay(1);
        print_r($res);die;
    }

    /**
     * 支付回调
     */
    public function notify(){

    }

    /**
     * 退款
     * @param string $transaction_id  平台订单号
     * @return mixed
     */
    public function refund($transaction_id = ''){
        $body = [
            'transaction_id' => $transaction_id,//平台订单号
            'out_refund_no' => $this->getOrderNo(),//系统退款单号
            'reason' => '退款',//退款原因
            'notify_url' => '',//退款回调
            'amount' => [
                'refund' => 1,//退款金额
                'total' => 1,//原订单金额
                'currency' => 'CNY',
            ],
        ];
        $headers = $this->sign('POST',$this->refundApi,json_encode($body));
        return $this->curl_post($this->refundApi,json_encode($body),$headers);
    }

	/**
     * 退款回调
     */
    public function refundNotify(){

    }
    
    /**
     * 签名
     * @param string $http_method    请求方式GET|POST
     * @param string $url            url
     * @param string $body           报文主体
     * @return array
     */
    public function sign($http_method = 'POST',$url = '',$body = ''){
        $mch_private_key = $this->getMchKey();//私钥
        $timestamp = time();//时间戳
        $nonce = $this->getRandomStr(32);//随机串
        $url_parts = parse_url($url);
        $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
        //构造签名串
        $message = $http_method."\n".
            $canonical_url."\n".
            $timestamp."\n".
            $nonce."\n".
            $body."\n";//报文主体
        //计算签名值
        openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');
        $sign = base64_encode($raw_sign);
        //设置HTTP头
        $config = $this->config();
        $token = sprintf('WECHATPAY2-SHA256-RSA2048 mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
            $config['mchid'], $nonce, $timestamp, $config['serial_no'], $sign);
        $headers = [
            'Accept: application/json',
            'User-Agent: */*',
            'Content-Type: application/json; charset=utf-8',
            'Authorization: '.$token,
        ];
        return $headers;
    }

    //私钥
    public function getMchKey(){
        //path->私钥文件存放路径
        $mchPrivateKey = '-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC0lvwqRdl2EVdg
lZtZScZ3K3qq/Oq1n8mrFJf7Kw9d4WfnhNoFAnwoi5H/Ep07H5pSzGwEDh59MVtS
5OkIeyGVT/thigytqPprDgGio7JbZ72yIFpPep+/SkfzFsDZM5Sk0ZVEWtxHZvpt
D2UIkfDvw5F++qNMIDYs9Tu7OOrecUJenEkUyj8HE4uHfk9D28ydoohf1vi7v+sh
GFwz+20bkvexuT5/tC6oA3Ux+YuSBtrTCXo3EwqFt8PmT5XTY+9Mcq7evPMMOF7q
MupM7e8AFx7GJZbY5tLupvcvbqYdGmGAslblAIMf695Frppr2N53Q+HC9uGrdmlp
I04xWW1nAgMBAAECggEBAJJ9b6wy4QX/Zyu38D5rtAxzPpx5cUNHjOW0XNynv11e
PVT21Yv+ygxxu0p4JQcSybKklHJtqZnQcc46VjZE+6cNLFOhEkvEqO4yfG0b8NBo
xN47lEaop/EaJmcwa9tFFizkvfqm4c0h4b6aIFDlYdZ8hAfG9LQJ5Shu/bcPoqYx
R7V0B4welxCUt/Z+UfQ4ZA9fbKCWMYmR/gIHK0XhDkjfBPQnsxbKE29qMw2r55SW
yT7BRxTZGSZW3Vsy8KLXHgABMww7/pRmZNCQ7HNPLAdcuJbXetSnZcMGcBin6sGY
qaLQb3I1f+jWxYfU59ypuCgXp4qa7JKTToLFT9ULcRECgYEA6SKyl0ZfsOZ+r0Zf
yDUWZSXBxjH1728rmFQ8sZHbx4tlqRoyFjdvwiBzxleqzU7hcfJrPmkyVWfR3Gcc
e5eHRqeSNcJwhmeC1cgCfQVBxVdOkc9X46w3fe/Ce0SagojGZP0bq2S+wPwT6iqe
7hE62tnnYmqXyEAnI2sJXl20ZTsCgYEAxk0HP0FU+ebHEs7Mc1cvOkMEJveJjtLY
uXJZuDole3d6Gt48NBF2LSGq7Tukk+cts+Ufc+TqAs/x9rQtkMNLHKmefv9t+YNk
GakSXSMsTjm0x093MkX+cES5uhbhacqSg56OChLfrSIgQE/7K6N3uikRkgwXmmik
eRz9FGJSJcUCgYA40T/9JiWEE2ikht4pCOcgV4dWKi7p34ocYcs463dItmxcPgoe
5/vQr+AHYq45wxOmlZIVb8XYkqjOskJ6zH8ndQdpGq4Z03hLaadRmMpisdhwKLwe
vIX5p0kaiamuTm8rhZQMvUzP859W3nRFSOWzGJAPqDK9lwTy2M87tFKWqQKBgCR3
feGwDgR24B0hUo/TdKfuMxFHbFCLjbdsw/sRFluCOT4/qCqbG3RpQJmn4jggx1LR
y9rwOeiSfRi1QbvhbiqzNqZ8Kqk79GiTowDluvwXuJr+jhj8rjHPMah7FLDzw8XY
np5Tojagk/W/v5zizt25N7X3609F9xker5vUCO9RAoGBAJMCEXiAk4iemE7PGcBs
FkBK9zrh7ZnKpWLWKZOPqVLHgl4vC+iVRw/EDazRz1Jqq7RPf36kBdxMblmzpuct
2VzJv0Ca8mhPyMGVdbiTtlMqYKlDsKb5soXM/NrnJ08kCvrxjwn3CsTt5vWpIUM3
+y6Dm1FUareTUfugU+oHC33D
-----END PRIVATE KEY-----
';
        return openssl_get_privatekey($mchPrivateKey);
    }

    //post请求
    public function curl_post($url , $data,$headers=array())
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        //设置header头
        curl_setopt($ch, CURLOPT_HTTPHEADER,$headers);
        // POST数据
        curl_setopt($ch, CURLOPT_POST, 1);
        // 把post的变量加上
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        $output = curl_exec($ch);
        curl_close($ch);
        return $output;
    }

    //get请求
    public function curl_get($url,$headers=array())
    {
        $info = curl_init();
        curl_setopt($info,CURLOPT_RETURNTRANSFER,true);
        curl_setopt($info,CURLOPT_HEADER,0);
        curl_setopt($info,CURLOPT_NOBODY,0);
        curl_setopt($info,CURLOPT_SSL_VERIFYPEER,false);
        curl_setopt($info,CURLOPT_SSL_VERIFYPEER,false);
        curl_setopt($info,CURLOPT_SSL_VERIFYHOST,false);
        //设置header头
        curl_setopt($info, CURLOPT_HTTPHEADER,$headers);
        curl_setopt($info,CURLOPT_URL,$url);
        $output = curl_exec($info);
        curl_close($info);
        return $output;
    }

    /**
     * 获得随机字符串
     * @param $len      integer       需要的长度
     * @param $special  bool      是否需要特殊符号
     * @return string       返回随机字符串
     */
    public function getRandomStr($len, $special=false){
        $chars = array(
            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
            "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
            "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G",
            "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
            "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2",
            "3", "4", "5", "6", "7", "8", "9"
        );

        if($special){
            $chars = array_merge($chars, array(
                "!", "@", "#", "$", "?", "|", "{", "/", ":", ";",
                "%", "^", "&", "*", "(", ")", "-", "_", "[", "]",
                "}", "<", ">", "~", "+", "=", ",", "."
            ));
        }

        $charsLen = count($chars) - 1;
        shuffle($chars);                            //打乱数组顺序
        $str = '';
        for($i=0; $i<$len; $i++){
            $str .= $chars[mt_rand(0, $charsLen)];    //随机取出一位
        }
        return $str;
    }

    /**
     * 生成订单号
     */
    public function getOrderNo(){
        return date('Ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
    }

    //H5测试支付
//    public function pay(){
//        $url = 'https://api.mch.weixin.qq.com/v3/pay/transactions/h5';
//        $body = [
//            'appid' => '******',
//            'mchid' => '******',
//            'description' => '******',
//            'out_trade_no' => date('YmdHis').rand(1000,9999),
//            'notify_url' => "******",
//            'amount' => [
//                'total' => 100,
//                'currency' => 'CNY'
//            ],
//            'scene_info' => [
//                'payer_client_ip' => Request::instance()->ip(),
//                'h5_info' => [
//                    'type' => 'Wap',
//                ],
//            ],
//        ];
//        $headers = $this->sign('POST',$url,json_encode($body));
//        $res = $this->curl_post($url,$body,$headers);
//        print_r($res);
//    }
}